from wineArea import Area
from countryArea import CountryArea
from regionArea import RegionArea
from appellationArea import AppellationArea, GroupAppellationArea
import levin.levinCommon as levinCommon

from utils import uuidID

class WorldArea(Area):
    numSelected = 0

    worldId = None
    synchroDict = {}

    _saveSynchronizedFile = None

    def setSelected(self):
        self._numSelected = True
    def toDict(self,user=False):
        d = super(WorldArea,self).toDict(user)
        if user:
            d['worldId'] = self.worldId
            d['synchroDict'] = self.synchroDict
        d['version']  = self.version
        return d
    
    def fromDict(self, d, user=False):
        print ' WorldArea fromDict v=',d.get('version',None)

        if user:
            self.worldId = d.get('worldId',0)
            self.synchroDict = d.get('synchroDict',{})
        else:
            self.version = d.get('version',0)
            
        super(WorldArea,self).fromDict(d,user)
        self._update_local_names()

    def readSystemData(self):
        d=super(WorldArea,self).readSystemData()
        self.version = d.get('version',None)

        self.sortSubAreas()
        #self.version = VERSION

    
    def dataPath(self):
        return 'data/World'


    def addWine(self, b):
        country = self[b.country]
        region  = country[b.region] if b.region else country
        latestA = region
        if b.groupAppellation:            
            groupAppellation  = region[b.groupAppellation]
            appellation = groupAppellation[b.appellation]
            latestA = appellation
        elif b.appellation:
            appellation = region.getSubAreaRec( b.appellation )
            if not appellation :
                appellation = region[ b.appellation ]
            latestA = appellation
        
        if not b.bottleId:
            b.bottleId = uuidID()
        latestA.addWine(b)

        
    def removeWine(self, b):
        area = b.parentArea
        area.wines.remove(b)
        ## for a in b.areaInheritance():
        ##     a.nWinesTotal -=1
        if area.wines == []:
            self.checkUserContent() # this resets the  needed flags


        
    def requestSaveContent(self, filename=''):
        """This function simply act as a redirection to saveUserContent.
        The redirection is usefull for globally changing the saving behaviour during tests"""
        if filename == '':
            filename = levinCommon.USER_SAVE
        self.saveUserContent(filename)

    def areaInheritance(self):
        return [self]


    def synchronizeWithFile(self, fname):
        o = WorldArea("World")
        o.loadContent( self._system_content, user=False )
        o.loadContent( fname , user=True)

        #print ' sync with file ', len(self._user_cepages) , len(o._user_cepages) 
        def saveFunc(*l):
            o.saveUserContent( fname)
            self.saveUserContent( self._user_content)
        self._saveSynchronizedFile = saveFunc

        self.synchronize(o)


    def synchronize(self, oworld):
        super(WorldArea,self).synchronize(oworld)
        # now synchronize bottles :
        now = datetime.datetime.now()
        sec1 = datetime.timedelta(seconds=1)
        lastSync = self.synchroDict.get(oworld.worldId, datetime.datetime.min)

        # create pairs 
        conflicting = []

        selfW = dict( (w.bottleId, w) for w in self.getWines() )
        selfWt = dict( selfW )
        oworldW = dict( (w.bottleId, w) for w in oworld.getWines() )

        for bid, w in selfWt.iteritems():
            aw = oworldW.pop(bid,None)
            #print ' Looking for  ',w, w.cru_name , aw, aw.cru_name if aw else 'Notfound'
            if aw :
                selfW.pop(bid)
                if w.lastUpdate> lastSync:
                    if aw.lastUpdate>lastSync:
                        conflicting.append( (w,aw) )
                    else:
                        #aw.updateFrom(w)
                        aw.replaceBy(w)
                elif aw.lastUpdate>lastSync:
                    #w.updateFrom(aw)
                    w.replaceBy(aw, useSelfParent=True)
                
        # remains only non-paired :
        for w in oworldW.values():
            #print self.worldId,' : adding ',(w.region, w.cru_name)
            self.addWine(w)
        for w in selfW.values():
            #print oworld.worldId,' : adding ',(w.region, w.cru_name)
            oworld.addWine(w)

        #print ' CONFLICTING  ', conflicting
        self.resolveConflict( conflicting)
        for sw,aw in conflicting:
            sw.lastUpdate = now
            sw.lastUpdate = now
        
        self.synchroDict[oworld.worldId] = now+sec1
        oworld.synchroDict[self.worldId] = now+sec1

    def resolveConflict(self,conflict):
        for sw, aw in conflict:
            print ' conflicting ', sw.cru_name , aw.cru_name
            self._resolveToLatest(sw,aw)

    def _resolveToLatest(self, sw,aw):
        if aw.lastUpdate > sw.lastUpdate:
            sw.replaceBy(aw, useSelfParent=True)
        else:
            aw.replaceBy(sw)
            
    def _addExistingBottle(self, b):
        country = self[b.country]
        region  = country[b.region] if b.region else country
        appellation  = groupAppellation[appellation] if appellation else groupAppellation

    def compare(self,o):
        d = collections.defaultdict(list)
        ok = super(WorldArea, self).compare(o,d)
        #print ' WorldArea compare = ',ok
        return d




_hierarchy = [ WorldArea, CountryArea , RegionArea, AppellationArea ]
for i,h in enumerate(_hierarchy[:-1]):
    sh = _hierarchy[i+1]
    h.subAreaClass = sh
    h.level = i
    sh.level =i+1
GroupAppellationArea.subAreaClass = AppellationArea
GroupAppellationArea.level = AppellationArea.level
AppellationArea.level = AppellationArea.level +1
